# -*- coding: utf8 -*-
##############################################################
#             Copyright (C), 2009-2013, ali
#
# FileName:   SDTestBase.py
# Author:     yixun.zengyx
# Version:    0.1
#
# Description:
#   TestCaseBase
#
#
# Function List:
#
#
# History:
#     <Author/Maintainer>      <Date>      <Modification>
#       yixun.zengyx        2013/03/23    Create this file
#############################################################

import codecs
import os
import types
#import pprint
#import json
import time
import re
from sys import stdout, exc_info
#import copy
from xml.dom.minidom import Document, parse
import itertools
from SDTRunner import *
from SDTReport import *
from Lib.Color import *
from Lib.SDTCode import *
from Lib.IData import *
import networkx as nx
import pdb
# pdb.set_trace()

class TestEnv:
    Env = {}

class XmlDataGenerator:
    def __init__(self, xmlTDT, nonXmlPrint=None, xmlStyleData=None):       
        self.xmlDoc = Document()
        self.xmlTDT = xmlTDT

        eleCount = 0
        self.eleMap = {}
        for eleTDT in self.xmlTDT:
            self.eleMap[eleTDT['name']] = eleCount
            if eleTDT.__contains__('alias'):
                for eName in eleTDT['alias']:
                    self.eleMap[eName] = eleCount
            eleTDT['ele'] = None
            if not eleTDT.__contains__('cls'):
                eleTDT['cls'] = eleTDT['findex'] + 1
            if not eleTDT.__contains__('sname'):
                eleTDT['sname'] = eleTDT['name']
            if not eleTDT.__contains__('must'):
                eleTDT['must'] = True
            eleCount += 1
        for eleTDT in self.xmlTDT:
            eleTDT['clslist'] = [index for index in range(0, eleCount) if self.xmlTDT[index]['cls'] > eleTDT['cls']]

        self.topEle = self.__CreateElement(self.xmlDoc, self.xmlTDT[0])
        if xmlStyleData != None:
            self.xmlDoc.insertBefore(self.xmlDoc.createProcessingInstruction("xml-stylesheet", xmlStyleData), self.topEle)

    def __GetFele(self, eleIndex):
        feleIndex = self.xmlTDT[eleIndex]['findex']
        feleTDT = self.xmlTDT[feleIndex]

        if feleIndex > 0:
            fele = feleTDT['ele']
            if fele == None:
                ffele = self.__GetFele(feleIndex)
                if feleTDT['must']:
                    fele = self.__CreateElement(ffele, feleTDT)
                else:
                    fele = ffele
            return fele
        else:
            return self.topEle

    def __CreateElement(self, fele, eleTDT, content=None, eleName=None, **eleAttrs):
        ele = self.xmlDoc.createElement(eleName if eleName != None else eleTDT['sname'])
        eleTDT['ele'] = ele
        fele.appendChild(ele)
        for eleAttr in eleAttrs.keys():
            ele.setAttribute(eleAttr, eleAttrs[eleAttr])
        if content != None:
            ele.appendChild(self.xmlDoc.createCDATASection(content))

        for index in eleTDT['clslist']:
            self.xmlTDT[index]['ele'] = None
        return ele

    def AddElement(self, eleName, content=None, **eleAttrs):
        eleIndex = self.eleMap[eleName]
        fele = self.__GetFele(eleIndex)
        self.__CreateElement(fele, self.xmlTDT[eleIndex], content, eleName, **eleAttrs)

    def __str__(self, indent="\t", newl="\n", encoding=None):
        return self.xmlDoc.toprettyxml(indent, newl, encoding)

class TestLogger:
    def __init__(self, logFilePath=None, isHtmlLog=False, isXmlLog=False):
        self.__isInHandler = False
        self.__htmlIsTrue = isHtmlLog
        if self.__htmlIsTrue:
            isXmlLog = False
        self.Init(logFilePath, isXmlLog)

    def Init(self, logFilePath, isXmlLog=False, xsl=""):
        if self.__isInHandler:
            return
        self.FilePath = logFilePath
        self.__logFile = None

        self.__LogLine = stdout.writelines
        tempTypeStr = logFilePath.__class__.__name__
        if tempTypeStr == 'str' or tempTypeStr == 'unicode':
            self.__logFile = codecs.open(logFilePath, "w", sys.stdin.encoding, buffering=0)
            self.__LogLine = self.__logFile.writelines
        elif logFilePath != None:
            self.__isInHandler = True
            self.__LogLine = logFilePath
        if self.__htmlIsTrue and (self.__logFile != None):
            self.InfoText("%s\r\n%s\r\n</head>\r\n<body>\r\n<pre>\r\n", "<html>\r\n<head>",'''<meta http-equiv="Content-Type" content="text/html; charset=%s" />'''%(sys.stdin.encoding))
        self.__isXmlLog = isXmlLog
        if isXmlLog:
            self.__xlog = XmlDataGenerator([
      {'name':'TestLog', 'findex':-1}
    , {'name':'TestCase', 'findex':0}
    , {'name':'Step', 'findex':1}
    , {'name':'Input', 'findex':2, 'must':False, 'alias':['Validate']}
    , {'name':'Info', 'findex':3, 'must':False, 'alias':['Success', 'Warn', 'Error']}
    , {'name':'Result', 'findex':1, 'must':False, 'cls':0}
], None if isXmlLog else self.InfoText, xsl)

    def __Log(self, levelIndex, eleName, content, **eleAttrs):
        try:
            if content != None:
                if type(content) is unicode:
                    content = "%s %s" % (time.strftime("[%Y-%m-%d %H:%M:%S]"), content.encode(sys.stdin.encoding))
                else:
                    content = "%s %s" % (time.strftime("[%Y-%m-%d %H:%M:%S]"), content)
            if self.__isXmlLog:
                self.__xlog.AddElement(eleName, content, **eleAttrs)
            else:
                eleAttrDesp = ""
                for eleAttr in eleAttrs.keys():
                    eleAttrDesp = eleAttrDesp + " [%s] %s" % (eleAttr, eleAttrs[eleAttr])
                if type(content) is unicode:
                    self.__LogLine("%s[%s] %s%s\r\n" % ("\r\n" if levelIndex == 0 else (levelIndex * 2 * " "),
                        eleName, content.encode(sys.stdin.encoding) if content != None else '', eleAttrDesp))
                else:
                    self.__LogLine("%s[%s] %s%s\r\n" % ("\r\n" if levelIndex == 0 else (levelIndex * 2 * " "),
                        eleName, content if content != None else '', eleAttrDesp))
        except Exception as ex:
            TestInfo.InfoText("Logging: %s", ex)

    def BeginTestCase(self, testcaseName, testcaseinfo):
        self.__Log(0, "TestCase", None, casename=testcaseName, param=testcaseinfo)

    def EndTestCase(self, caseName, result, rescode, executetime, moduleName='', testclassName=''):
        self.__Log(1, "Result", None, casename=caseName, result=result, rescode=str(rescode), time=str(executetime), moduleName=str(moduleName), testclassName=str(testclassName))

    def Step(self, log):
        self.__Log(1, "Step", None, description=log)

    def Input(self, log):
        self.__Log(2, "Input", None, description=log)

    def Validate(self, log):
        self.__Log(2, "Validate", None, description=log)

    def Info(self, log):
        self.__Log(3, "Info", log)

    def Success(self, log):
        self.__Log(3, "Success", log)

    def Warn(self, log):
        self.__Log(3, "Warn", log)
        
    def Fail(self,log):
        self.__Log(4,"Fail",log)
        
    def Skip(self,log):
        self.__Log(4,"Skip",log)

    def Error(self, log):
        self.__Log(4, "Error", log)

    def InfoText(self, formator, *args):
        if formator != None:
            self.__LogLine(formator % args if len(args) > 0 else formator)
            self.__LogLine("\r\n")

    def Close(self):
        if self.__isXmlLog:
            self.__LogLine(str(self.__xlog))
        if self.__logFile != None:
            if self.__htmlIsTrue:
                self.InfoText("%s","\r\n</pre>\r\n</body>\r\n</html>\r\n")
            self.__logFile.close()
            self.__LogLine = stdout.writelines

Logger = TestLogger()
TestInfo = TestLogger(None, False)

class PyRegExp:
    def __init__(self, pattern, pattonMaxlen=30720):
        self.patterns = []
        if pattern == "":
            self.patterns.append("")
        else:
            startIndex = 0
            while startIndex >= 0:
                endIndex = pattern.find("|", (startIndex + pattonMaxlen))
                self.patterns.append(pattern[startIndex if pattern[startIndex] != '|' else (startIndex + 1):endIndex if endIndex > 0 else len(pattern)])
                startIndex = endIndex
    def IsMatch(self, pyStr):
        try:
            return self.Match(pyStr) != None
        except:
            return False
    def Match(self, pyStr):
        for pattern in self.patterns:
            mcher = re.match(pattern, pyStr)
            if mcher != None:
                return (pattern, mcher)
    def __str__(self):
        bufStr = ""
        for pStr in self.patterns:
            if bufStr != "":
                bufStr += "|"
            else:
                bufStr += pStr
        return bufStr
    def __repr__(self):
        return str(self)

class SDTConst:
    BeginTestCaseInfo = "\t%s Running ..."
    EndTestCaseInfo = "%s:\t%s"
    SuccessEqualInfo ="Assert %s Equal, in fact %s Equal, Is OK"
    EqualInfo = "Assert %sEqual, in fact %sEqual: Expected \"%s\", Actual \"%s\" for \"%s\""
    ConditionInfo = "Assert %s, in fact %s for %s"
    SuccessConditionInfo = "Assert %s, Is OK"
    SuccessEqualLargerInfo = "Assert %s Equal or Larger %s , Is OK"
    EqualLargerInfo = "Assert %s Equal or Larger, in fact %s Equal or Larger: Expected \"%s\", Actual \"%s\" for \"%s\""
    SysFunReg = PyRegExp('__.+__|BeginTestCase|EndTestCase|SetUp|TearDown|Property|Assert|Logger')

    Passed = 0
    Warned = 1
    Failed = 2
    NotRun = 3

class TestCheck(Exception):
    pass


class InputStatusCheck(Exception):
    pass

class Assertion:
    
    def __init__(self,ResultLog=None):
        if ResultLog==None:
            self.LOG = Logger
        else:
            self.LOG = ResultLog
        

    def stepChecker(self, msg , expectedValue, actualValue, checkType='=='):
        '''
        Used to check a necessary step is correct, if failure will cause a WARNING exception
        '''
        if checkType == '==':
            if expectedValue != actualValue:
                self.LOG.Fail(msg, expectedValue, actualValue)
        elif checkType == 'in':
            if actualValue not in expectedValue:
                self.LOG.Fail(msg, expectedValue, actualValue)    
        else:
            self.LOG.Fail('unsupported check type', expectedValue, actualValue)           

                        
    def assertEqual(self, msg , expectedValue, actualValue):
        Assert.AreEqual(expectedValue, actualValue, msg,log=self.LOG)

    def assertNotEqual(self, msg , expectedValue, actualValue):
        Assert.AreNotEqual(expectedValue, actualValue, msg,log=self.LOG)

    def assertIn(self, msg, member, container):
        isInContainer = member in container
        Assert.IsTrue(isInContainer, msg + ' : %s %s in %s' % (member, isInContainer, container),log=self.LOG)
        
    def assertInList(self,msg,removeList,member,container,noMatch=[]):
        isInContainer = Assert.AreEqualInList(msg, member, container,removeList=removeList,noMatch=noMatch,log=self.LOG)
        Assert.IsTrue(isInContainer, "Not In TargetList",log=self.LOG)
            
            
    def assertNotIn(self, msg, member, container):
        isInContainer = member in container
        Assert.IsTrue(not isInContainer, msg + ' : %s  %s not in %s' % (member, isInContainer, container),log=self.LOG)
                        
    def assertTrue(self, msg , condition):
        Assert.IsTrue(condition, msg,log=self.LOG)
                       
    def assertGreater(self, msg, big, small):
        Assert.IsTrue(big > small, msg,log=self.LOG)

    def assertInDict(self, msg, subdic, fdict):
        """Checks whether actual is a superset of expected."""

        missing = {}
        for key in subdic.keys():
            if key not in fdict.keys():
                missing[key] = subdic[key]
            else:
                if subdic[key] != fdict[key]:
                    missing[key] = subdic[key]
        Assert.IsTrue(not missing, msg,log=self.LOG)

    def assertListNoOrderEqual(self, msg, expectedList, actualList):
        '''
        Check list no order equals with each others
        '''
        set1 = set(expectedList)
        set2 = set(actualList)
        difference1 = set1.difference(set2)
        difference2 = set2.difference(set1)
        if not (difference1 or difference2):
            self.LOG.Info("%s. exp:%s, act:%s" % (msg, expectedList, actualList))
        else:
            lines = []
            if difference1:
                for item in difference1:
                    lines.append(item)
            if difference2:
                for item in difference2:
                    lines.append(item)

            raise TestCheck(msg + '>>> Not equal items are in list:' + str(lines))
        
    def assertJsonString(self,msg,removeList,expectedJsonString,actualJsonString):
        Assert.AreEqualJsonString(expectedJsonString, actualJsonString, msg,removeList=removeList,log=self.LOG)
        
    def assertDict(self,msg,removeList,expectedDict,actualDict,noMatch=[]):
        Assert.AreEqualDict(expectedDict, actualDict, msg,removeList=removeList,noMatch=noMatch,log=self.LOG)
            
    def assertRegexpMatches(self, msg, expected_regex, text):
        if isinstance(expected_regex, (str, bytes)):
            expected_regex = re.compile(expected_regex)
        if not expected_regex.search(text):
            msg = msg or "Regexp didn't match"
            msg = '%s: %r not found in %r' % (msg, expected_regex.pattern, text)
            raise TestCheck(msg) 
        else:
            msg = msg or "Regexp match is True"
            msg = '%s: %r found in %r' % (msg, expected_regex.pattern, text)            
            self.LOG.Info(msg) 

class Assert:
    IsWarned = False
    @staticmethod
    def AssumeEqual(expectedValue, actualValue, msg,log=None):            
        if expectedValue != actualValue:
            if log==None:
                Logger.Warn(SDTConst.EqualInfo % ("", "NOT ", expectedValue, actualValue, msg))
            else:
                log.Warn(SDTConst.EqualInfo % ("", "NOT ", expectedValue, actualValue, msg))
            Assert.IsWarned = True

    @staticmethod
    def AssumeTrue(condition, msg,log=None):            
        if not condition:
            if log==None:
                Logger.Warn(SDTConst.ConditionInfo % ("True", "False", msg))
            else:
                log.Warn(SDTConst.ConditionInfo % ("True", "False", msg))
            Assert.IsWarned = True

    # precondition or condition Checker
    @staticmethod
    def AreEqual(expectedValue, actualValue, msg,log=None):
        if expectedValue != actualValue:
            if log==None:
                Logger.Fail(SDTConst.EqualInfo % ("", "NOT ", expectedValue, actualValue, msg))
            else:
                log.Fail(SDTConst.EqualInfo % ("", "NOT ", expectedValue, actualValue, msg))
            raise TestCheck(SDTConst.EqualInfo % ("", "NOT ", expectedValue, actualValue, msg))
        if log==None:
            Logger.Success(SDTConst.EqualInfo % ("", "", expectedValue, actualValue, msg))
        else:
            log.Success(SDTConst.EqualInfo % ("", "", expectedValue, actualValue, msg))

    @staticmethod
    def AreNotEqual(expectedValue, actualValue, msg,log=None):
        if expectedValue == actualValue:
            if log==None:
                Logger.Fail(SDTConst.EqualInfo % ("Not ", "", expectedValue, actualValue, msg))
            else:
                log.Fail(SDTConst.EqualInfo % ("Not ", "", expectedValue, actualValue, msg))
            raise TestCheck(SDTConst.EqualInfo % ("Not ", "", expectedValue, actualValue, msg))
        if log==None:
            Logger.Success(SDTConst.SuccessEqualInfo % (expectedValue, actualValue))
        else:
            log.Success(SDTConst.SuccessEqualInfo % (expectedValue, actualValue))

    @staticmethod
    def AreEqualOrLarger(expectedValue, actualValue, msg,log=None):
        if expectedValue > actualValue:
            if log==None:
                Logger.Fail(SDTConst.EqualInfo % ("", "NOT ", expectedValue, actualValue, msg))
            else:
                log.Fail(SDTConst.EqualInfo % ("", "NOT ", expectedValue, actualValue, msg))
            raise TestCheck(SDTConst.EqualLargerInfo % ("", "NOT ", expectedValue, actualValue, msg))
        if log==None:
            Logger.Success(SDTConst.SuccessEqualLargerInfo % (expectedValue,actualValue))
        else:
            log.Success(SDTConst.SuccessEqualLargerInfo % (expectedValue,actualValue))

    @staticmethod
    def IsTrue(condition, msg,log=None):
        if not condition:
            if log==None:
                Logger.Fail(SDTConst.ConditionInfo % ("True", "False", msg))
            else:
                log.Fail(SDTConst.ConditionInfo % ("True", "False", msg))
            raise TestCheck(SDTConst.ConditionInfo % ("True", "False", msg))
        if log==None:
            Logger.Success(SDTConst.SuccessConditionInfo % ("True"))
        else:
            log.Success(SDTConst.SuccessConditionInfo % ("True"))

    @staticmethod
    def CaptureIfAreEqual(expectedValue, actualValue, funPoint,log=None): 
        Assert.AreEqual(expectedValue, actualValue, funPoint,log=log)
        
    @staticmethod
    def AreEqualJsonString(expectedValue, actualValue, msg,removeList=[],log=None):
        expList = expectedValue.split(',')
        actualList = actualValue.split(',')
        if len(expList)!=len(actualList):
            if log==None:
                Logger.Fail(SDTConst.EqualInfo % ("", "NOT ", expectedValue, actualValue, msg))
            else:
                log.Fail(SDTConst.EqualInfo % ("", "NOT ", expectedValue, actualValue, msg))
            raise TestCheck(SDTConst.EqualInfo % ("", "NOT ", expectedValue, actualValue, msg))
        count = len(expList) - 1
        for i in range(0,count):
            expStr = expList[i]
            actStr = actualList[i]
            isRemove = False
            for removeStr in removeList:
                if removeStr in expStr:
                    isRemove = True
                    break
            if isRemove:
                continue
            if expStr != actStr:
                if log==None:
                    Logger.Fail(SDTConst.EqualInfo % ("", "NOT ", expStr, actStr, msg))
                else:
                    log.Fail(SDTConst.EqualInfo % ("", "NOT ", expStr, actStr, msg))
                raise TestCheck(SDTConst.EqualInfo % ("", "NOT ", expStr, actStr, msg))
        if log==None:
            Logger.Success(SDTConst.EqualInfo % ("", "", expectedValue, actualValue, msg))
        else:
            log.Success(SDTConst.EqualInfo % ("", "", expectedValue, actualValue, msg))
    
    @staticmethod
    def AreEqualInList(msg, member, container,removeList=[],noMatch=[],log=None):
        if (type(member) is list) and (type(container) is list):
            member = Assert._ListSort_(member,removeList)
            container = Assert._ListSort_(container,removeList)
            member.sort()
            container.sort()
            resultIn = False
            while len(member)>0:
                resultIn = False
                item = member.pop(0)
                for targetItem in container:
                    resultIn = Assert.__IsSame__(item,targetItem,msg,removeList=removeList,noMatch=noMatch,log=log)
                    if resultIn:
                        break
            return resultIn
        else:
            if log==None:
                Logger.Warn(SDTConst.EqualInfo % ("", "Type NOT ", type(member), type(container), msg))
            else:
                log.Warn(SDTConst.EqualInfo % ("", "Type NOT ", type(member), type(container), msg))
            return False
            
    @staticmethod
    def __IsSame__(expectedValue, actualValue, msg,removeList=[],noMatch=[],log=None,currentKey=""):
        print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
        print "expectedValue:"
        print expectedValue
        print "\n\n\nactualValue:"
        print actualValue
        print "\n\ncurrentKey:"
        print currentKey
        print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
        print "\n\n\n"
        if type(actualValue) is unicode:
            actualValue = actualValue.encode(sys.stdin.encoding)
        if type(expectedValue) is unicode:
            expectedValue = expectedValue.encode(sys.stdin.encoding)
        actualType = type(actualValue)
        expectType = type(expectedValue)
        if log==None:
            Logger.Info("CurrentKey is : %s"%(currentKey))
        else:
            log.Info("CurrentKey is : %s"%(currentKey))
        if actualType!=expectType:
#             if not (((actualType is str) and (expectType is unicode)) or ((expectType is str) or (actualType is unicode))):
            if log==None:
                Logger.Fail(SDTConst.EqualInfo % ("", "Type NOT ", expectType, actualType, msg))
            else:
                log.Fail(SDTConst.EqualInfo % ("", "Type NOT ", expectType, actualType, msg))
            return False
        if actualType is list:
#             pdb.set_trace()
            expectedValue = Assert._ListSort_(expectedValue,removeList)
            actualValue = Assert._ListSort_(actualValue,removeList)
#             pdb.set_trace()
            if len(actualValue) != len(expectedValue):
                if log==None:
                    Logger.Fail(SDTConst.EqualInfo % ("", "List Count NOT ", expectedValue, actualValue, msg))
                else:
                    log.Fail(SDTConst.EqualInfo % ("", "List Count NOT ", expectedValue, actualValue, msg))
                return False
            actualValue.sort()
            expectedValue.sort()
            print "AreEqualDict List Sort============================"
            print expectedValue
            print actualValue
            print "AreEqualDict List Sort============================"
            i = 0
            while len(actualValue)>0:
                actObj = actualValue.pop(0)
                expObj = expectedValue.pop(0)
                currentKey = currentKey+"[%d]"%(i)
                Assert.__IsSame__(expObj, actObj, msg,removeList=removeList,noMatch=noMatch,log=log,currentKey=currentKey)
                i = i + 1
        elif actualType is dict:
            expKeys = expectedValue.keys()
            actKeys = actualValue.keys()
            for item in removeList:
                if item in expKeys:
                    expKeys.remove(item)
                if item in actKeys:
                    actKeys.remove(item)
            expKeys.sort()
            actKeys.sort()
            if len(expKeys)!=len(actKeys):
                if log==None:
                    Logger.Fail(SDTConst.EqualInfo % ("", "Keys NOT ", expKeys, actKeys, msg))
                else:
                    log.Fail(SDTConst.EqualInfo % ("", "Keys NOT ", expKeys, actKeys, msg))
                return False
            while len(actKeys)>0:
                actKey = expKeys.pop(0)
                expKey = actKeys.pop(0)
                if (actKey==expKey):
                    if expKey in noMatch:
                        continue
                    if currentKey=="":
                        currentKey = actKey
                    else:
                        currentKey = currentKey+"->"+actKey
                    return Assert.__IsSame__(expectedValue.pop(expKey), actualValue.pop(actKey), msg,removeList=removeList,noMatch=noMatch,log=log,currentKey=currentKey)
                else:
                    print "__IsSame__==========================="
                    print expKeys
                    print actKeys
                    print "__IsSame__==========================="
                    if log==None:
                        Logger.Fail(SDTConst.EqualInfo % ("", "Key NOT ", expKey, actKey, msg))
                    else:
                        log.Fail(SDTConst.EqualInfo % ("", "Key NOT ", expKey, actKey, msg))
                    return False
        elif actualType is tuple:
            expectedValue = list(expectedValue)
            actualValue = list(actualValue)
            return Assert.__IsSame__(expectedValue, actualValue, msg,removeList=removeList,noMatch=noMatch,log=log,currentKey=currentKey)
        else:
            if log==None:
                Logger.Info("CurrentKey is : %s"%(currentKey))
            else:
                log.Info("CurrentKey is : %s"%(currentKey))
            if expectedValue != actualValue:
                if log==None:
                    Logger.Fail(SDTConst.EqualInfo % ("", "NOT ", expectedValue, actualValue, msg))
                else:
                    log.Fail(SDTConst.EqualInfo % ("", "NOT ", expectedValue, actualValue, msg))
                return False
            else:
                return True
            
        
    
    @staticmethod
    def _ListSort_(sourceList,removeList=[]):
        if type(sourceList) is list:
            targetValue = []
            while len(sourceList)>0:
                resultValue = Assert._ListSort_(sourceList.pop(0),removeList)
                targetValue.append(resultValue)
            return targetValue
        elif type(sourceList) is dict:
            sourceList = Assert.__DelDictField__(sourceList,removeList)
            soruceKeys = sourceList.keys()
            for item in soruceKeys:
                if (type(sourceList[item]) is tuple) or (type(sourceList[item]) is list):
                    sourceList[item] = Assert._ListSort_(sourceList[item],removeList)
            return sourceList
        elif type(sourceList) is tuple:
            Assert._ListSort_(list(sourceList),removeList)
        else:
            return sourceList
            
    
    
    @staticmethod
    def __DelDictField__(sourceValue,removeList=[]):
        if type(sourceValue) is dict:
            soruceKeys = sourceValue.keys()
            for item in soruceKeys:
                if item in removeList:
                    sourceValue.pop(item)
        return sourceValue

            
            
            
            
            
    @staticmethod
    def AreEqualDict(expectedValue, actualValue, msg,removeList=[],noMatch=[],log=None,currentKey=""):
        print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
        print "expectedValue:"
        print expectedValue
        print "\n\n\nactualValue:"
        print actualValue
        print "\n\ncurrentKey:"
        print currentKey
        print "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"
        print "\n\n\n"
        if type(actualValue) is unicode:
            actualValue = actualValue.encode(sys.stdin.encoding)
        if type(expectedValue) is unicode:
            expectedValue = expectedValue.encode(sys.stdin.encoding)
        actualType = type(actualValue)
        expectType = type(expectedValue)
        if log==None:
            Logger.Info("CurrentKey is : %s"%(currentKey))
        else:
            log.Info("CurrentKey is : %s"%(currentKey))
        if actualType!=expectType:
#             if not (((actualType is str) and (expectType is unicode)) or ((expectType is str) or (actualType is unicode))):
            if log==None:
                Logger.Fail(SDTConst.EqualInfo % ("", "Type NOT ", expectType, actualType, msg))
            else:
                log.Fail(SDTConst.EqualInfo % ("", "Type NOT ", expectType, actualType, msg))
            raise TestCheck(SDTConst.EqualInfo % ("", "Type NOT ", expectType, actualType, msg))
        if actualType is list:
#             pdb.set_trace()
            expectedValue = Assert._ListSort_(expectedValue,removeList)
            actualValue = Assert._ListSort_(actualValue,removeList)
#             pdb.set_trace()
            if len(actualValue) != len(expectedValue):
                if log==None:
                    Logger.Fail(SDTConst.EqualInfo % ("", "List Count NOT ", expectedValue, actualValue, msg))
                else:
                    log.Fail(SDTConst.EqualInfo % ("", "List Count NOT ", expectedValue, actualValue, msg))
                raise TestCheck(SDTConst.EqualInfo % ("", "List Count NOT ", expectedValue, actualValue, msg))
            actualValue.sort()
            expectedValue.sort()
            print "AreEqualDict List Sort============================"
            print expectedValue
            print actualValue
            print "AreEqualDict List Sort============================"
            i = 0
            while len(actualValue)>0:
                actObj = actualValue.pop(0)
                expObj = expectedValue.pop(0)
                currentKey = currentKey+"[%d]"%(i)
                Assert.AreEqualDict(expObj, actObj, msg,removeList=removeList,noMatch=noMatch,log=log,currentKey=currentKey)
                i = i + 1
        elif actualType is dict:
            expKeys = expectedValue.keys()
            actKeys = actualValue.keys()
            for item in removeList:
                if item in expKeys:
                    expKeys.remove(item)
                if item in actKeys:
                    actKeys.remove(item)
            expKeys.sort()
            actKeys.sort()
            if len(expKeys)!=len(actKeys):
                if log==None:
                    Logger.Fail(SDTConst.EqualInfo % ("", "Keys NOT ", expKeys, actKeys, msg))
                else:
                    log.Fail(SDTConst.EqualInfo % ("", "Keys NOT ", expKeys, actKeys, msg))
                raise TestCheck(SDTConst.EqualInfo % ("", "Keys NOT ", expKeys, actKeys, msg))
            while len(actKeys)>0:
                actKey = expKeys.pop(0)
                expKey = actKeys.pop(0)
                if (actKey==expKey):
                    if expKey in noMatch:
                        continue
                    if currentKey=="":
                        currentKey = actKey
                    else:
                        currentKey = currentKey+"->"+actKey
                    Assert.AreEqualDict(expectedValue.pop(expKey), actualValue.pop(actKey), msg,removeList=removeList,noMatch=noMatch,log=log,currentKey=currentKey)
                else:
                    print "AreEqualDict==========================="
                    print expKeys
                    print actKeys
                    print "AreEqualDict==========================="
                    if log==None:
                        Logger.Fail(SDTConst.EqualInfo % ("", "Key NOT ", expKey, actKey, msg))
                    else:
                        log.Fail(SDTConst.EqualInfo % ("", "Key NOT ", expKey, actKey, msg))
                    raise TestCheck(SDTConst.EqualInfo % ("", "Key NOT ", expKey, actKey, msg))
        elif actualType is tuple:
            expectedValue = list(expectedValue)
            actualValue = list(actualValue)
            Assert.AreEqualDict(expectedValue, actualValue, msg,removeList=removeList,noMatch=noMatch,log=log,currentKey=currentKey)
        else:
            if log==None:
                Logger.Info("CurrentKey is : %s"%(currentKey))
            else:
                log.Info("CurrentKey is : %s"%(currentKey))
            Assert.AreEqual(expectedValue, actualValue, msg,log=log)
            
        
       

class TestCaseBase:
    def __init__(self,IData=[None]):
        self.Assert = None
        self.Logger = None
        self.Param = {}
        self.Group = None
        self.Context = None
        self.IData=IData#用来给整个流程测试提供数据源，直到IData中的数据源为空，才停止，当随机模式时，用这个值来进行多线程并行
        self.DS = None
        
    def __repr__(self):
        return "self"

    def SetUp(self):
        pass

    def TearDown(self):
        pass

    def BeginTestCase(self):
        pass

    def EndTestCase(self):
        pass

    def ErrorHandle(self, errorException, caseInfo):
        pass

    def __deepcopy__(self, memo=None):
        return self
    
class SDTestCaseBase(TestCaseBase):
    '''
    @param End:一种为字串，直接是表示一个最终状态的名称，另一种为一个List，表示有好几种方式，都是最终的 
    '''
    def __init__(self,Begin="Start",End="End",IData=[None]):
        TestCaseBase.__init__(self,IData)
        self.Current_Status_Init = Begin
        self.EndStatus_Init = End
        self.Init()
        
        
    def Init(self):
        self.Current_Status = self.Current_Status_Init
        self.EndStatus = self.EndStatus_Init
        self.Next_Status = None
        self.fail = False
        self.error = False
        self.sdindex = 0
        self.SDM = All_Simple_Paths
        self.G = nx.DiGraph()
        self.sdlist = []
        
    def IsCurrent(self,Status):
        if Status<>None:
            Status = Status.decode("utf8")
        if self.Current_Status == Status:
            return True
        else:
            return False
        
    def IsNext(self,Status):
        if Status<>None:
            Status = Status.decode("utf8")
        if self.Next_Status == Status:
            return True
        else:
            return False


def TestCase(Param={},Context=None,Group=None,  sFrom=None, sTo=None,  **SearchKey):
    '''
    @param sFrom: StatusName 
    @param sTo: [("ToStatusName",weight)...] or [("ToStatusName",weight,event)...] ps:event must tcname
    '''
    def __TestCaseFun(testCaseFun):
        def TestCaseDecorator(tObj,*arg):
            tObj.Group = Group
            isdebug = False
            if len(arg)>0:
                if arg[0].lower()=="show":
                    if not isinstance(tObj, SDTestCaseBase):
                        return tObj
                    else:
                        if sTo is not None:
                            for TupleTo in sTo:
                                if len(TupleTo)==2:
                                    sToName,weight = TupleTo
                                    event = testCaseFun.__name__
                                else:
                                    sToName,weight,event = TupleTo
                                    if event==None:
                                        event = testCaseFun.__name__
                                tObj.G.add_edge(sFrom.decode(sys.stdin.encoding),sToName.decode(sys.stdin.encoding),label=event,weight=weight,tc=testCaseFun.__name__)
                        return tObj
                else:
                    Runner = arg[4]
                    if not isinstance(tObj, SDTestCaseBase):
                        FilterGroup = arg[5]
                        if FilterGroup==None or Group==FilterGroup:
                            if arg[0].lower()=="debug":
                                isdebug = True
                            return Loader.execMethod(Runner, "RunTestCase",tObj,arg[1]+"."+testCaseFun.__name__, lambda:testCaseFun(tObj), Param, Context,Group, sFrom, sTo,isdebug,arg[2],arg[3])
                    else:
                        if arg[0].lower()=="debug":
                                isdebug = True
                        return Loader.execMethod(Runner, "RunTestCase",tObj,arg[1]+"."+testCaseFun.__name__, lambda:testCaseFun(tObj), Param, Context,Group, sFrom, sTo,isdebug,arg[2],arg[3])
#                     return Runner.RunTestCase(tObj,arg[1]+"."+testCaseFun.__name__, lambda:testCaseFun(tObj), Param, Context,Group, sFrom, sTo,isdebug,arg[2],arg[3],arg[4])
        return TestCaseDecorator
    return __TestCaseFun


def TestClass(ClassName="", **SearchKey):
    def __ClassMiddleFun(cObj):
        def ClassDecorator():
            tclist=[]
            for caseFun in dir(cObj):
                if not SDTConst.SysFunReg.IsMatch(caseFun):
                    if getattr(cObj,caseFun).__name__=='TestCaseDecorator':
                        tclist.append(caseFun)
#                         print cObj.__name__
#                         print cObj.__module__
#                         print cObj.TestResult
            return cObj(),tclist
        return ClassDecorator
    return __ClassMiddleFun

if __name__ == '__main__':
    pass
    #Assert.AreNotEqual('Check displayName','af',"afafa")
#     a,tclist = TestC()
#     a.test1()
    #print a.__doc__
    #c.AreEqual(1,1,"assert")